package net.yegong;

import java.awt.image.BufferedImage;
import java.awt.image.WritableRaster;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;

import javax.imageio.ImageIO;

public class DiffMain {
	private static final String PREFIX;

	private static final int BANDS;
	private static final int ROWS;
	private static final int COLS;

	static {
		Scanner sc = new Scanner(System.in);
		System.out.println("Please input the file prefix");
		PREFIX = "data\\" + sc.next();
		System.out.println("Please input the bands");
		BANDS = sc.nextInt();
		System.out.println("Please input the rows");
		ROWS = sc.nextInt();
		System.out.println("Please input the columns");
		COLS = sc.nextInt();
	}

	private static final File SOURCE_FILE = new File(PREFIX + ".source.bin");
	private static final File TARGET_FILE = new File(PREFIX + ".output.bin");
	private static final File OUTPUT_FILE = new File(PREFIX + ".diff.png");

	private static final int BLOCK_SIZE = 10;

	public static void main(String[] argv) throws Exception {
		byte[] source = new byte[BANDS * ROWS * COLS];
		byte[] target = new byte[BANDS * ROWS * COLS];
		read(source, SOURCE_FILE);
		read(target, TARGET_FILE);
		Map<Integer, Integer> distribution = diffData(source, target);
		showDistribution(distribution);
		int[][] diff = diffMap(source);
		writeImage(diff);
	}

	private static void writeImage(int[][] data) throws IOException {
		int rows = data.length;
		int cols = data[0].length;

		int width = cols;
		int height = rows;
		BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY);
		WritableRaster raster = (WritableRaster) image.getData();
		for (int i = 0; i < width; ++i) {
			for (int j = 0; j < height; ++j) {
				int value = data[j][i];
				raster.setSample(i, j, 0, value);
			}
		}
		image.setData(raster);
		ImageIO.write(image, "png", OUTPUT_FILE);
	}

	private static void showDistribution(Map<Integer, Integer> distribution) {
		float sum = BANDS * ROWS * COLS;
		float cum = 0.0f;
		for (int i = 0; i < 500; ++i) {
			if (distribution.containsKey(i)) {
				int count = distribution.get(i);
				float percent = count / sum;
				cum += percent;
				System.out.printf("%3d\t%10d\t%1.2f\t%1.2f\n", i, count, percent, cum);
			}
		}
	}

	private static Map<Integer, Integer> diffData(byte[] source, byte[] target) {
		Map<Integer, Integer> distribution = new HashMap<Integer, Integer>();
		assert (source.length == target.length);
		int length = source.length;
		for (int i = 0; i < length; ++i) {
			int diff = source[i] - target[i];
			diff = Math.abs(diff);
			Integer value = distribution.get(diff);
			if (null == value) {
				value = 0;
			}
			value += 1;
			distribution.put(diff, value);
			//distribution map
			diff = Math.min(10, diff);
			source[i] = (byte) diff;
		}
		return distribution;
	}

	private static int[][] diffMap(byte[] diff) {
		int rows = ROWS / BLOCK_SIZE;
		int cols = COLS / BLOCK_SIZE;
		int[][] map = new int[rows][cols];
		int max = Integer.MIN_VALUE;
		for (int i = 0; i < rows; ++i) {
			for (int j = 0; j < cols; ++j) {
				int value = getBlockSum(diff, i, j);
				map[i][j] = value;
				max = Math.max(value, max);
			}
		}
		for (int i = 0; i < rows; ++i) {
			for (int j = 0; j < cols; ++j) {
				map[i][j] = map[i][j] * 255 / max;
			}
		}
		System.out.printf("Max Block Diff : %d\n", max);
		return map;
	}

	private static int getBlockSum(byte[] data, int row, int col) {
		int sum = 0;
		for (int i = row * BLOCK_SIZE; i < (row + 1) * BLOCK_SIZE; ++i) {
			for (int j = col * BLOCK_SIZE; j < (col + 1) * BLOCK_SIZE; ++j) {
				for (int k = 0; k < BANDS; ++k) {
					int value = get(data, i, j, k);
					assert (value >= 0);
					assert (value <= 10);
					sum += value;
				}
			}
		}
		return sum;
	}

	private static byte get(byte[] data, int row, int col, int band) {
		return data[(row * COLS + col) * BANDS];
	}

	private static void read(byte[] data, File file) throws IOException {
		InputStream is = null;
		try {
			is = new BufferedInputStream(new FileInputStream(file));
			int count = is.read(data);
			assert (count == data.length);
		}
		finally {
			if (null != is) {
				is.close();
			}
		}
	}
}
